﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using InvestmentIntelligence.Data.Repository.EFImplementation;
using InvestmentIntelligence.DB;
using InvestmentIntelligence.DbModel.CustomModels;
using InvestmentIntelligence.DbModel.Models;

namespace InvestmentIntelligence.Data.Repository.SqlImplementation
{
    public class InvestmentBenchmarkSerieRepository : IIPRepository<InvestmentBenchmarkSerie>, IInvestmentBenchmarkSerieRepository
    {
        private const int MergeTimeout = 300;

        public void Merge(IEnumerable<InvestmentBenchmarkSerie> items, MergeArea area)
        {
            if (area.IdeaIds != null)
            {
                MergeOverIdeas(items, area.IdeaIds);
            }
            else
            {
                MergeOverFundBook(items, area.FundBookId);
            }
        }

        public void MergeOverFundBook(IEnumerable<InvestmentBenchmarkSerie> items, int fundBookId)
        {
            const string targetTableSearchCondition = "i.FundBookEntityId = @FundBook";
            var parameters = new[]
                                     {
                                         new KeyValuePair<string, object>("@FundBook", fundBookId)
                                     };
            Merge(items, targetTableSearchCondition, parameters);
        }

        public void MergeOverIdeas(IEnumerable<InvestmentBenchmarkSerie> items, IEnumerable<Guid> ideaIds)
        {
            var targetTableSearchCondition = String.Format("[IdeaId] IN ({0})", String.Join(",", ideaIds.Select(i => String.Format("'{0}'", i))));
            var parameters = new KeyValuePair<string, object>[0];
            Merge(items, targetTableSearchCondition, parameters);
        }

        private string CreateTempTable(DataConnection dc)
        {
            var name = "##InvestmentBenchmarkSerie" + Guid.NewGuid().ToString().Replace("-", "");
            dc.Execute(string.Format("SELECT * INTO {0} FROM [Analytics].[InvestmentBenchmarkSerie] WHERE 1=2", name), CommandType.Text);
            return name;
        }

        private void Merge(IEnumerable<InvestmentBenchmarkSerie> items, string serchCondition, IEnumerable<KeyValuePair<string, object>> parameters)
        {
            using (var dc = new DataConnection())
            {
                dc.Timeout = MergeTimeout;
                dc.Begin();

                var tableName = CreateTempTable(dc);
                dc.BulkCopy(tableName, items);
                ExecuteMerge(dc, tableName, serchCondition, parameters);

                dc.Commit();
            }
        }

        private void ExecuteMerge(DataConnection dc, string tempTable, string searchCondition, IEnumerable<KeyValuePair<string, object>> parameters)
        {
            const string mergePattern = @"
WITH series AS (
    SELECT 
        bs.* 
    FROM
        [Analytics].[InvestmentBenchmarkSerie] bs
    LEFT JOIN
        [Analytics].[Investment] i
    ON
        i.Id = bs.InvestmentId
    WHERE
        {1}
)
MERGE
	series s
USING
	{0} st
ON
	s.[InvestmentId] = st.[InvestmentId] AND s.[SecurityId] = st.[SecurityId] AND s.[Date] = st.[Date]
WHEN MATCHED THEN 
	UPDATE SET s.[RoC] = st.[RoC],
               s.[BenchmarkId] = st.[BenchmarkId],
               s.[PositionPnL] = st.[PositionPnL],
               s.[PositionFxPnL] = st.[PositionFxPnL]
WHEN NOT MATCHED THEN 
	INSERT ([InvestmentId],[Date],[SecurityId],[BenchmarkId],[PositionPnL],[PositionFxPnL],[RoC])
    VALUES ([InvestmentId],[Date],[SecurityId],[BenchmarkId],[PositionPnL],[PositionFxPnL],[RoC])
WHEN NOT MATCHED BY SOURCE THEN
	DELETE
OPTION (MAXDOP 1)
;
";
            var sqlCode = string.Format(mergePattern, tempTable, searchCondition);
            foreach (var p in parameters)
            {
                dc.Parameters.AddWithValue(p.Key, p.Value);
            }
            dc.Execute(sqlCode, CommandType.Text);
        }

    }
}
